#pragma once
#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <strings.h>
#include <string>
#include <assert.h>
#include <arpa/inet.h>
#include <functional>
#include "InertAddr.hpp"
#include "Log.hpp"

using namespace LogModule;

using funcType = std::function<void(int, std::string, InertAddr)>;

class UdpServer
{
private:
    int _socketfd;
    uint16_t _port;
    funcType _func;

public:
    UdpServer(uint16_t port, const funcType &func)
        : _socketfd(-1), _port(port), _func(func)
    {
    }
    void Init()
    {
        // 打开网络文件
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);

        if (_socketfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket() fail";
            exit(1);
        }
        else
        {
            LOG(LogLevel::INFO) << "socket() had succeeded _socketfd:" << _socketfd;
        }

        sockaddr_in sd;
        bzero(&sd, sizeof(sd));
        sd.sin_family = AF_INET;
        sd.sin_port = htons(_port);
        sd.sin_addr.s_addr = INADDR_ANY;
        int n = bind(_socketfd, (const sockaddr *)&sd, sizeof(sd));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind fail";
            exit(1);
        }
        else
        {
            LOG(LogLevel::INFO) << "bind has successed";
        }
    }

    void Start()
    {
        while (true)
        {
            // 收各个客户端发来的消息
            sockaddr_in client;
            socklen_t len = sizeof(client);
            char buffer[1024];
            int n = recvfrom(_socketfd, buffer, sizeof(buffer)-1, 0, (sockaddr *)&client, &len);
            if(n<=0)
            {
                    // 处理错误（n == -1）或连接关闭（n == 0）
                perror("recvfrom failed");
                return;
            }
            buffer[n] = '\0';

            _func(_socketfd, std::string(buffer), InertAddr(client));
        }
    }
    ~UdpServer()
    {
    }
};